package com.gscitysfy.cus.drain.modules.inspection.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.gscitysfy.cloudfrmwk.data.mybatis.HerodotusIdentifierGenerator;
import com.gscitysfy.cloudfrmwk.security.utils.SecurityUtils;
import com.gscitysfy.cus.drain.config.BusinessException;
import com.gscitysfy.cus.drain.constants.DicConstant;
import com.gscitysfy.cus.drain.constants.RedisKeyConstant;
import com.gscitysfy.cus.drain.modules.common.service.IFileService;
import com.gscitysfy.cus.drain.modules.common.vo.PageVo;
import com.gscitysfy.cus.drain.modules.inspection.entity.DrainInspectionMnOrder;
import com.gscitysfy.cus.drain.modules.inspection.entity.DrainInspectionMnPlan;
import com.gscitysfy.cus.drain.modules.inspection.entity.DrainInspectionMnProblem;
import com.gscitysfy.cus.drain.modules.inspection.mapper.DrainInspectionMnOrderMapper;
import com.gscitysfy.cus.drain.modules.inspection.service.IDrainInspectionMnJobService;
import com.gscitysfy.cus.drain.modules.inspection.service.IDrainInspectionMnOrderService;
import com.gscitysfy.cus.drain.modules.inspection.service.IDrainInspectionMnPlanService;
import com.gscitysfy.cus.drain.modules.inspection.service.IDrainInspectionMnProblemService;
import com.gscitysfy.cus.drain.modules.inspection.vo.*;
import com.gscitysfy.cus.drain.modules.pipe.service.IDrainPipeNetworkJobService;
import com.gscitysfy.cus.drain.utils.DateUtil;
import com.gscitysfy.cus.drain.utils.HttpResponseUtil;
import com.gscitysfy.cus.drain.utils.RedisUtil;
import jodd.util.StringUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.http.util.Asserts;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Stream;

/**
 * @author Administrator
 * @since 2022-10-14 16:15:41
 */
@Service
public class DrainInspectionMnOrderServiceImpl extends ServiceImpl<DrainInspectionMnOrderMapper, DrainInspectionMnOrder> implements IDrainInspectionMnOrderService {

    @Resource
    private IDrainInspectionMnProblemService problemService;

    @Resource
    private IDrainInspectionMnPlanService planService;

    @Resource
    private IDrainInspectionMnJobService jobService;

    @Resource
    private IDrainPipeNetworkJobService pipeJobService;

    @Resource
    private IFileService fileService;

    @Resource
    private DrainInspectionMnOrderMapper orderMapper;

    @Resource
    HerodotusIdentifierGenerator herodotusIdentifierGenerator;

    /**
     * 逗号分隔符
     */
    public static final String SPLIT_COMMA = ",";

    /**
     * 复核通过
     */
    public static final Integer REAUDIT_PASS = 1;

    /**
     * 生成
     */
    public static final Integer PROBLEM_IS_CREATE_ORDER = 1;

    /**
     * 前缀名
     */
    public static final String PREFIX_WORD = "WYRW";

    /**
     * 结果类别：无法处置
     */
    public static final String CANNOT_DEAL_TYPE = "0";

    /**
     * 结果类别：处置完成
     */
    public static final String ALREADY_DONE_TYPE = "1";

    /**
     * 处置任务状态：待处置
     */
    public static final Long WAITTING_FOR_DEAL_TYPE = 0L;

    /**
     * 处置任务状态：处置中
     */
    public static final Long DEALING_TYPE = 1L;

    /**
     * 问题审核状态，0表待审核，1表示审核通过，2表示审核不通过
     */
    public static final Integer WAITTING_FOR_AUDIT_STATE = 0;

    /**
     * 问题审核状态，0表待审核，1表示审核通过，2表示审核不通过
     */
    public static final Integer PASSING_FOR_AUDIT_STATE = 1;

    public static final String PLATFORM_ADMIN = "平台管理员";

    /**
     * 否
     */
    public static final String IS_PROBLEM_GENERATE_ORDER = "0";

    /**
     * 任务来源（0问题创建 1计划创建 2上报问题创建）
     */
    public static final String PROBLEM_GENERATE_ORDER = "0";

    /**
     * 任务来源（0问题创建 1计划创建 2上报问题创建）
     */
    public static final String DIRECT_GENERATE_ORDER = "2";

    /**
     * 0(直接上报问题)，1(巡检中上报问题)
     */
    public static final Integer DIRECT_GENERATE_PROBLEM_TYPE = 0;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public IPage<DrainInspectionMnOrder> pageList(DrainInspectionMnOrderQueryVo queryVo) {
        return orderMapper.getPageList(new Page<>(queryVo.getCurrent(), queryVo.getSize()), queryVo);
    }

    @Override
    public DrainInspectionMnOrderDetailVo detailById(Long id) {
        Assert.notNull(id, "id");
        DrainInspectionMnOrder order = this.getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("处置详情数据为空!");
        }
        DrainInspectionMnOrderDetailVo detailVo = new DrainInspectionMnOrderDetailVo();
        BeanUtils.copyProperties(order, detailVo);

        //现根据是否是维养任务来展示详情  0否(展示问题详情) 1是(展示计划详情)
        if (IS_PROBLEM_GENERATE_ORDER.equals(detailVo.getIsOrder())) {
            //关联问题
            Long pId = order.getCmProblemId();
            if (Objects.nonNull(pId)) {
                DrainInspectionMnProblem problem = problemService.getById(pId);
                Map<Object, Object> problemTypeDic = redisUtil.hmget(RedisKeyConstant.DATA_DICT_KEY + DicConstant.PLAN_OBJECT_TYPE);
                if (!Objects.isNull(problem)) {
                    detailVo.setProblemVo(problem);
                    if (!problemTypeDic.isEmpty() && StringUtil.isNotEmpty(problem.getCmProblemType())) {
                        detailVo.setCmProblemTypeDesc(problemTypeDic.get(problem.getCmProblemType()).toString());
                    }
                    //问题的经纬度
                    detailVo.setCmProblemLocationDetail(problem.getCmProblemLocationDetail());
                    detailVo.setCmProblemLocationLat(problem.getCmProblemLocationLat());
                    detailVo.setCmProblemLocationLng(problem.getCmProblemLocationLng());
                    //问题附件
                    if (StringUtils.isNotBlank(problem.getCmProblemAttachment())) {
                        detailVo.setProblemFiles(fileService.getFileListByIds(problem.getCmProblemAttachment()));
                    }
                }
            }
        } else {
            //关联计划
            Long pid = order.getCmPlanId();
            if (Objects.nonNull(pid)) {
                DrainInspectionMnPlan plan = planService.getById(pid);
                //字典
                Map<Object, Object> planBasis = redisUtil.hmget(RedisKeyConstant.DATA_DICT_KEY + DicConstant.PLAN_BASIS);
                Map<Object, Object> planType = redisUtil.hmget(RedisKeyConstant.DATA_DICT_KEY + DicConstant.PLAN_TYPE);
                Map<Object, Object> planObjectType = redisUtil.hmget(RedisKeyConstant.DATA_DICT_KEY + DicConstant.PLAN_OBJECT_TYPE);
                Map<Object, Object> planFrequency = redisUtil.hmget(RedisKeyConstant.DATA_DICT_KEY + DicConstant.PLAN_FREQUENCY);
                if (!Objects.isNull(plan)) {
                    detailVo.setPlanVo(plan);
                    if (!planBasis.isEmpty() && StringUtil.isNotEmpty(plan.getCmPlanBasis())) {
                        detailVo.setCmPlanBasisDesc(planBasis.get(plan.getCmPlanBasis()).toString());
                    }
                    if (!planType.isEmpty() && StringUtil.isNotEmpty(plan.getCmPlanType())) {
                        detailVo.setCmPlanTypeDesc(planType.get(plan.getCmPlanType()).toString());
                    }
                    if (!planObjectType.isEmpty() && StringUtil.isNotEmpty(plan.getCmPlanObjectType())) {
                        detailVo.setCmPlanObjectTypeDesc(planObjectType.get(plan.getCmPlanObjectType()).toString());
                    }
                    if (!planFrequency.isEmpty() && StringUtil.isNotEmpty(plan.getCmPlanFrequency())) {
                        detailVo.setCmPlanFrequencyDesc(planFrequency.get(plan.getCmPlanFrequency()).toString());
                    }
                }
            }
        }
        //处置前附件
        if (StringUtils.isNotBlank(order.getCmOrderBeforeAttachment())) {
            detailVo.setDispositionBeforeFiles(fileService.getFileListByIds(order.getCmOrderBeforeAttachment()));
        }
        //处置后附件
        if (StringUtils.isNotBlank(order.getCmOrderAfterAttachment())) {
            detailVo.setDispositionAfterFiles(fileService.getFileListByIds(order.getCmOrderAfterAttachment()));
        }
        return detailVo;
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public boolean deleteByIds(String ids) {
        Asserts.notBlank(ids, "ids");
        List<Long> idList = Lists.newArrayList();
        Stream.of(ids.split(SPLIT_COMMA)).forEach(id -> {
            DrainInspectionMnOrder order = this.getById(Long.parseLong(id));
            if (Objects.isNull(order)) {
                throw new BusinessException("维修单数据不存在!");
            }
            idList.add(Long.parseLong(id));
        });
        return this.removeBatchByIds(idList);
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public boolean reAudit(Long id, Integer state, String comment) {
        Asserts.notNull(id, "id");
        DrainInspectionMnOrder order = this.getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("维修单数据不存在!");
        }
        order.setCmOrderApprovalStatus(state);
        order.setCmOrderApprovalComments(comment);
        return this.updateById(order);
    }

    @Override
    public IPage<DrainInspectionMnOrder> todayTodo(PageVo page) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Date today = DateUtil.getDate(formatter.format(new Date()));
        String userId = "";
        String name = SecurityUtils.getPrincipal().getName();
        if (StringUtils.isNotEmpty(name) && !PLATFORM_ADMIN.equals(name)) {
            userId = SecurityUtils.getPrincipal().getUserId();
        }
        return orderMapper.getTodayTodo(new Page<>(page.getCurrent(), page.getSize()), today, userId);
    }

    @Override
    public void exportInfos(String ids, HttpServletResponse response) {
        Asserts.notBlank(ids, "id");
        try {
            List<Long> idList = Lists.newArrayList();
            Stream.of(ids.split(SPLIT_COMMA)).forEach(id -> idList.add(Long.parseLong(id)));
            ExcelWriter writer = ExcelUtil.getWriter(true);
            writer.setOnlyAlias(true);
            String filename = "维养任务单.xlsx";
            Map<String, String> headerMap = Maps.newLinkedHashMap();
            headerMap.put("cmOrderNo", "处置任务编号");
            headerMap.put("cmOrderStartTime", "处置开始时间");
            headerMap.put("cmOrderEndTime", "处置结束时间");
            headerMap.put("cmProblemType", "问题类别");
            headerMap.put("cmOrderHeaderName", "处置负责人");
            headerMap.put("cmOrderHeaderPhone", "负责人联系电话");
            headerMap.put("cmOrderExecutorName", "处置人");
            headerMap.put("cmOrderResult", "处置结果类别");
            headerMap.put("isOrder", "是否养护任务");
            headerMap.put("cmOrderStatus", "处置任务状态");
            headerMap.put("cmOrderApprovalStatus", "复核状态");

            //设置表头
            headerMap.forEach(writer::addHeaderAlias);
            List<Map<String, Object>> dataList = Lists.newArrayList();
            List<DrainInspectionMnOrder> list = orderMapper.getList(idList);
            Map<Object, Object> problemType = redisUtil.hmget(RedisKeyConstant.DATA_DICT_KEY + DicConstant.PLAN_OBJECT_TYPE);
            list.forEach(item -> {
                Map<String, Object> dataMap = Maps.newLinkedHashMap();
                dataMap.put("cmOrderNo", null == item.getCmOrderNo() ? "" : item.getCmOrderNo());
                dataMap.put("cmOrderStartTime", null == item.getCmOrderStartTime() ? "" : item.getCmOrderStartTime());
                dataMap.put("cmOrderEndTime", null == item.getCmOrderEndTime() ? "" : item.getCmOrderEndTime());
                dataMap.put("cmProblemType", null == problemType ? "" : problemType.get(item.getCmProblemType()).toString());
                dataMap.put("cmOrderHeaderName", null == item.getCmOrderHeaderName() ? "" : item.getCmOrderHeaderName());
                dataMap.put("cmOrderHeaderPhone", null == item.getCmOrderHeaderPhone() ? "" : item.getCmOrderHeaderPhone());
                dataMap.put("cmOrderExecutorName", null == item.getCmOrderExecutorName() ? "" : item.getCmOrderExecutorName());
                if (CANNOT_DEAL_TYPE.equals(item.getCmOrderResult())) {
                    item.setCmOrderResult("无法处置");
                } else if (ALREADY_DONE_TYPE.equals(item.getCmOrderResult())) {
                    item.setCmOrderResult("处置完成");
                }
                dataMap.put("cmOrderResult", null == item.getCmOrderResult() ? "" : item.getCmOrderResult());
                if (WAITTING_FOR_DEAL_TYPE.equals(item.getCmOrderStatus())) {
                    item.setCmOrderStatusDesc("待处置");
                } else if (DEALING_TYPE.equals(item.getCmOrderStatus())) {
                    item.setCmOrderStatusDesc("处置中");
                } else {
                    item.setCmOrderStatusDesc("已处置");
                }
                dataMap.put("cmOrderStatus", null == item.getCmOrderStatus() ? "" : item.getCmOrderStatusDesc());
                if (WAITTING_FOR_AUDIT_STATE.equals(item.getCmOrderApprovalStatus())) {
                    item.setCmOrderApprovalStatusDesc("待复核");
                } else if (PASSING_FOR_AUDIT_STATE.equals(item.getCmOrderApprovalStatus())) {
                    item.setCmOrderApprovalStatusDesc("复核通过");
                } else {
                    item.setCmOrderApprovalStatusDesc("复核不通过");
                }
                dataMap.put("cmOrderStatus", null == item.getCmOrderStatus() ? "" : item.getCmOrderStatusDesc());
                if (IS_PROBLEM_GENERATE_ORDER.equals(item.getIsOrder())) {
                    item.setIsOrderDesc("否");
                } else {
                    item.setIsOrderDesc("是");
                }
                dataMap.put("isOrder", null == item.getIsOrder() ? "" : item.getIsOrderDesc());
                dataList.add(dataMap);
            });
            if (CollectionUtils.isEmpty(dataList)) {
                List<String> stringList = Lists.newArrayList();
                headerMap.forEach((k, v) -> stringList.add(v));
                writer.writeHeadRow(stringList);
            }
            writer.write(dataList, true);
            HttpResponseUtil.setResponseHeaders(response, filename);
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out, true);
        } catch (IOException e) {
            log.error("导出维养任务单异常");
        }
    }

    @Override
    public DrainInspectionMnOrderVo reGenerateDetail(Long id) {
        Asserts.notNull(id, "cmKid");
        DrainInspectionMnOrder order = this.getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("维修单数据不存在!");
        }
        DrainInspectionMnProblem problem = problemService.getById(order.getCmProblemId());
        if (!Objects.isNull(problem) && REAUDIT_PASS.equals(problem.getCmProblemApprovalStatus())) {
            throw new BusinessException("抱歉,复核已通过的任务单暂不支持重新生成!");
        }
        //历史记录
        List<DrainInspectionMnOrder> history = this.list(Wrappers.<DrainInspectionMnOrder>query().eq("cm_problem_id", order.getCmProblemId()));
        DrainInspectionMnOrderVo orderVo = new DrainInspectionMnOrderVo();
        orderVo.setHistory(history);
        return orderVo;
    }

    @Override
    public boolean reGenerate(DrainInspectionMnOrderVo orderVo) {
        Asserts.notNull(orderVo.getCmProblemId(), "problemId");
        DrainInspectionMnProblem problem = problemService.getById(orderVo.getCmProblemId());
        DrainInspectionMnOrder order = new DrainInspectionMnOrder();
        BeanUtils.copyProperties(orderVo, order);
        //修改问题是否生成维养单状态
        if (!Objects.isNull(problem)) {
            problem.setCmProblemIsCreateOrder(PROBLEM_IS_CREATE_ORDER);
            problemService.updateById(problem);
            //直接上报问题
            if (DIRECT_GENERATE_PROBLEM_TYPE.equals(problem.getProblemType())) {
                //直接上报问题创建
                order.setSourceType(DIRECT_GENERATE_ORDER);
            } else {
                //巡检等产生的问题所创建
                order.setSourceType(PROBLEM_GENERATE_ORDER);
            }
        }
        order.setCmKid(herodotusIdentifierGenerator.nextId(order).longValue());
        order.setCmOrderNo(generateWord());
        //待处置状态
        order.setCmOrderStatus(0L);
        //待复核
        order.setCmOrderApprovalStatus(0);
        return this.save(order);
    }

    @Override
    public boolean dispose(DrainInspectionMnOrderDisposeVo disposeVo) {
        Asserts.notNull(disposeVo.getCmKid(), "cmKid");
        DrainInspectionMnOrder order = this.getById(disposeVo.getCmKid());
        if (Objects.isNull(order)) {
            throw new BusinessException("维修单数据不存在!");
        }
        DrainInspectionMnOrder updateVo = new DrainInspectionMnOrder();
        BeanUtils.copyProperties(disposeVo, updateVo);
        updateVo.setCmOrderReportUserId(Long.valueOf(SecurityUtils.getPrincipal().getUserId()));
        try {
            Double sludge = Double.valueOf(disposeVo.getSludgeQuantity());
            updateVo.setSludgeQuantity(sludge);
        } catch (NumberFormatException e) {
            throw new BusinessException("污泥量类型输入错误，请输入数字!");
        }
        updateVo.setCmOrderActualEndTime(new Date());
        //已处置状态
        updateVo.setCmOrderStatus(2L);
        return this.updateById(updateVo);
    }

    @Override
    public List<MiniProgramCountVo> countProblemBasis() {
        try {
            AppQueryVo queryVo = new AppQueryVo();
            String name = SecurityUtils.getPrincipal().getName();
            String userId = SecurityUtils.getPrincipal().getUserId();
            if (StringUtils.isNotEmpty(name) && !PLATFORM_ADMIN.equals(name)) {
                queryVo.setUserId(userId);
            }
            ArrayList<MiniProgramCountVo> list = Lists.newArrayList();
            //巡查问题
            MiniProgramCountVo inspectionVo = new MiniProgramCountVo();
            Long inspectionCnt = orderMapper.countInspection(queryVo);
            inspectionVo.setBasisName("巡查问题");
            inspectionVo.setCnt(inspectionCnt);
            list.add(inspectionVo);
            //上报问题
            MiniProgramCountVo reportVo = new MiniProgramCountVo();
            Long reportCnt = orderMapper.countReport(queryVo);
            reportVo.setBasisName("上报问题");
            reportVo.setCnt(reportCnt);
            list.add(reportVo);
            //养护任务
            MiniProgramCountVo maintainVo = new MiniProgramCountVo();
            Long maintainCnt = orderMapper.countMaintain(queryVo);
            maintainVo.setBasisName("养护任务");
            maintainVo.setCnt(maintainCnt);
            list.add(maintainVo);
            //管网检测
            MiniProgramCountVo myPipeTaskVo = pipeJobService.countPipeTask();
            list.add(myPipeTaskVo);
            return list;
        } catch (Exception e) {
            throw new BusinessException("统计失败!");
        }
    }

    @Override
    public boolean updateState(Long id) {
        Asserts.notNull(id, "id");
        DrainInspectionMnOrder order = this.getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("维修单数据不存在!");
        }
        order.setCmOrderActualStartTime(new Date());
        order.setCmOrderStatus(1L);
        return this.updateById(order);
    }

    @Override
    public List<MiniProgramCountVo> miniProgramCount() {
        List<MiniProgramCountVo> results = new ArrayList<>();
        MiniProgramCountVo myMaintain = this.countMyMaintain();
        if (Objects.nonNull(myMaintain)) {
            results.add(myMaintain);
        }
        MiniProgramCountVo myXs = jobService.countMyXs();
        if (Objects.nonNull(myXs)) {
            results.add(myXs);
        }
        MiniProgramCountVo myJc = jobService.countMyJc();
        if (Objects.nonNull(myJc)) {
            results.add(myJc);
        }
        MiniProgramCountVo myPipeTask = pipeJobService.countPipeTask();
        if (Objects.nonNull(myPipeTask)) {
            results.add(myPipeTask);
        }
        return results;
    }

    /**
     * 统计我的养护
     *
     * @return MiniProgramCountVo 统计
     */
    public MiniProgramCountVo countMyMaintain() {
        AppQueryVo queryVo = new AppQueryVo();
        String name = SecurityUtils.getPrincipal().getName();
        String userId = SecurityUtils.getPrincipal().getUserId();
        if (StringUtils.isNotEmpty(name) && !PLATFORM_ADMIN.equals(name)) {
            queryVo.setUserId(userId);
        }
        //养护任务 待处置的
        Long maintainCnt = orderMapper.countMaintain(queryVo);
        MiniProgramCountVo problemBasisVo = new MiniProgramCountVo();
        problemBasisVo.setBasisName("我的养护");
        problemBasisVo.setCnt(maintainCnt);
        return problemBasisVo;
    }

    @Override
    public IPage<DrainInspectionMnOrder> getAppPageList(AppQueryVo queryVo) {
        return orderMapper.getAppPageList(new Page<>(queryVo.getCurrent(), queryVo.getSize()), queryVo);

    }

    /**
     * 生成编号
     *
     * @return String 编号
     */
    public String generateWord() {
        String code = PREFIX_WORD + DateUtil.formatDate(new Date(), DateUtil.yyyy_MM_dd_HH_mm);

        LambdaQueryWrapper<DrainInspectionMnOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(DrainInspectionMnOrder::getCmOrderNo, code).orderByDesc(DrainInspectionMnOrder::getCmAddtime).last("limit 1");
        DrainInspectionMnOrder order = this.getOne(queryWrapper);
        if (!Objects.isNull(order)) {
            String preNo = order.getCmOrderNo();
            String time = preNo.substring(preNo.length() - 3);
            String num = preNo.substring(0, preNo.length() - 3);
            DecimalFormat format = new DecimalFormat("000");
            code = time + format.format(Integer.parseInt(num) + 1);
        } else {
            code = code + "001";
        }
        return code;
    }
}
